package com.mall.util.distributed.raft.consensus;

import com.google.common.base.Strings;
import com.mall.util.distributed.raft.node.Node;
import com.mall.util.distributed.raft.node.NodeRole;
import com.mall.util.distributed.raft.rpc.message.AppendEntries;
import com.mall.util.distributed.raft.rpc.message.RequestVote;
import com.mall.util.distributed.raft.rpc.message.ResponseAppendEntries;
import com.mall.util.distributed.raft.rpc.message.ResponseVote;
import lombok.var;

import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;

public class DefaultConsensus implements Consensus {

    public final ReentrantLock voteLock = new ReentrantLock();

    @Override
    public ResponseVote requestVote(RequestVote requestVote) {
        try {
            var node = Node.getINSTANCE();
            var responseVote = new ResponseVote();

            if (!voteLock.tryLock()) {
                responseVote.setVoteGranted(false);
                responseVote.setTerm(node.getCurrentTerm().get());
                return responseVote;
            }

            var term = requestVote.getTerm();

            /* 如果对方任期没有自己新，不进行授权，并告知对方修改自己的任期 */
            if (term < node.getCurrentTerm().get()) {
                responseVote.setVoteGranted(false);
                responseVote.setTerm(node.getCurrentTerm().get());
                return responseVote;
            } else {
                /* 如果当前结点没有进行过投票或者投过票的结点是当前请求的候选者结点 */
                if (Strings.isNullOrEmpty(node.getVoteFor()) ||
                        node.getVoteFor().equals(requestVote.getCandidateId())) {

                    /* 当前结点确保切换成follower结点 */
                    node.setNodeRole(NodeRole.FOLLOWER);
                    node.setLeaderId(requestVote.getCandidateId());
                    node.setCurrentTerm(new AtomicLong(responseVote.getTerm()));
                    node.setVoteFor(requestVote.getCandidateId());

                    responseVote.setVoteGranted(true);
                    responseVote.setTerm(node.getCurrentTerm().get());
                    return responseVote;
                }
            }
            responseVote.setVoteGranted(false);
            responseVote.setTerm(node.getCurrentTerm().get());
            return responseVote;
        }finally {
            voteLock.unlock();
        }
    }

    @Override
    public ResponseAppendEntries appendEntries(AppendEntries appendEntries) {
        var node = Node.getINSTANCE();
        node.setPreElectionTimeout(System.currentTimeMillis());
        node.setPreHeartBeatTime(System.currentTimeMillis());

        return null;
    }
}
